iT邦幫忙

2026 iThome 鐵人賽

DAY 12
0
Software Development

Android 鐵人賽: 天命最高 - 陪伴大家一步步打造屬於自己的app系列 第 12

Android 點擊事件實戰——計數器、圖片切換與 ImageButton

  • 分享至 

  • xImage
  •  

Day 12:Android 點擊事件實戰——計數器、圖片切換與 ImageButton

昨天認識了 Android 常用的 Widget,今天要進一步練習 Android 的點擊事件。透過四個 MainActivity 範例,學習如何使用 View Binding、findViewById()、Lambda、View.OnClickListenerwhen,讓按鈕真正控制畫面上的文字與圖片。參考資料:Android Developers-輸入事件

今天會完成以下功能:

  • 使用 View Binding 操作多個按鈕。
  • 製作增加、減少及歸零的計數器。
  • 讓多個按鈕共用同一個事件監聽器。
  • 使用 when 判斷被點擊的元件。
  • 使用 ImageView 動態切換圖片。
  • 使用 ImageButton 建立圖片按鈕選單。
  • 比較 Lambda 與 View.OnClickListener 的差異。

參考資料:Android Developers-ButtonAndroid Developers-View Binding


一、什麼是點擊事件?

Android App 顯示畫面後,程式通常會等待使用者操作。例如按下登入按鈕、切換圖片、增加購物車數量或選擇功能。這些操作都屬於輸入事件。參考資料:Android Developers-輸入事件

Android 可以透過 setOnClickListener() 監聽元件的點擊事件:

button.setOnClickListener {
    // 使用者按下按鈕後執行的程式
}

當使用者按下 button,大括號裡的程式就會被執行。這種寫法使用 Kotlin Lambda,可以省略完整的匿名類別與 onClick() 函式。參考資料:Android Developers-回應點擊事件


範例一:使用 View Binding 操作三個按鈕

第一個範例使用 View Binding 取得 XML 中的三個按鈕及三個 TextView。按下不同按鈕後,程式會修改對應的文字。參考資料:Android Developers-View Binding

完整程式

package com.example.layout3

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.layout3.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    // 宣告 activity_main.xml 對應的 View Binding 物件。
    // lateinit 代表稍後會在 onCreate() 中進行初始化。
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 啟用 Edge-to-Edge,讓內容可以延伸至系統列區域。
        enableEdgeToEdge()

        // 根據 activity_main.xml 建立 ActivityMainBinding。
        binding = ActivityMainBinding.inflate(layoutInflater)

        // binding.root 代表 XML 最外層的根 View。
        setContentView(binding.root)

        // 取得狀態列及導覽列的 Insets,
        // 再將其設定成根版面的 Padding,避免畫面遭系統列遮住。
        ViewCompat.setOnApplyWindowInsetsListener(binding.main) { view, insets ->

            val systemBars =
                insets.getInsets(WindowInsetsCompat.Type.systemBars())

            view.setPadding(
                systemBars.left,
                systemBars.top,
                systemBars.right,
                systemBars.bottom
            )

            insets
        }

        // 第一個按鈕被點擊後,修改第一個 TextView。
        binding.button1.setOnClickListener {
            binding.textViewText1.text = "Button-1 Clicked"
        }

        // 第二個按鈕被點擊後,修改第二個 TextView。
        binding.button2.setOnClickListener {
            binding.textViewText2.text = "Button-2 Clicked"
        }

        // 第三個按鈕被點擊後,修改第三個 TextView。
        binding.button3.setOnClickListener {
            binding.textViewText3.text = "Button-3 Clicked"
        }
    }
}

參考資料:Android Developers-在 Activity 使用 View Binding

View Binding 如何取得元件?

View Binding 會依照 XML 檔名自動產生 Binding 類別。例如:

activity_main.xml
        ↓
ActivityMainBinding

XML 元件的 ID 也會轉換成 Binding 屬性:

<Button
    android:id="@+id/button1" />

在 Kotlin 中便可以透過以下方式取得:

binding.button1

因此不需要另外撰寫:

val button1 = findViewById<Button>(R.id.button1)

View Binding 可以減少重複程式碼,也能在編譯階段檢查元件 ID 與型別。參考資料:Android Developers-View Binding 與 findViewById


使用 Lambda 設定點擊事件

第一個範例使用 Lambda 處理按鈕事件:

binding.button1.setOnClickListener {
    binding.textViewText1.text = "Button-1 Clicked"
}

它相當於以下完整匿名物件寫法:

binding.button1.setOnClickListener(
    object : android.view.View.OnClickListener {

        override fun onClick(view: android.view.View?) {
            binding.textViewText1.text = "Button-1 Clicked"
        }
    }
)

由於 View.OnClickListener 只有一個抽象函式 onClick(),Kotlin 可以利用 SAM 轉換,簡化成 Lambda。參考資料:Kotlin-SAM conversions


範例二:製作加減歸零計數器

第二個範例使用三個按鈕製作計數器:

按鈕 ID 功能
button_plus 數值加一
button_minus 數值減一
button_reset 數值歸零

三個按鈕沒有分別建立 Lambda,而是共同使用 MyButton 事件監聽器,再透過 when 判斷實際被點擊的按鈕。參考資料:Android Developers-View.OnClickListener

MainActivity(8).kt 完整程式

package com.example.widget_2

import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat

class MainActivity : AppCompatActivity() {

    // 宣告歸零、減一及加一按鈕。
    private lateinit var buttonReset: Button
    private lateinit var buttonMinus: Button
    private lateinit var buttonPlus: Button

    // 顯示目前計數結果的 TextView。
    private lateinit var textViewCounter: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 啟用 Edge-to-Edge 顯示。
        enableEdgeToEdge()

        // 載入 activity_main.xml。
        setContentView(R.layout.activity_main)

        // 處理狀態列與導覽列範圍。
        ViewCompat.setOnApplyWindowInsetsListener(
            findViewById(R.id.main)
        ) { view, insets ->

            val systemBars =
                insets.getInsets(WindowInsetsCompat.Type.systemBars())

            view.setPadding(
                systemBars.left,
                systemBars.top,
                systemBars.right,
                systemBars.bottom
            )

            insets
        }

        // 使用 findViewById() 取得 XML 中的元件。
        textViewCounter =
            findViewById(R.id.txt_CountValue)

        buttonPlus =
            findViewById(R.id.button_plus)

        buttonMinus =
            findViewById(R.id.button_minus)

        buttonReset =
            findViewById(R.id.button_reset)

        // 建立一個共用的事件監聽器物件。
        val buttonListener = MyButton()

        // 三個按鈕共同使用相同的事件監聽器。
        buttonPlus.setOnClickListener(buttonListener)
        buttonMinus.setOnClickListener(buttonListener)
        buttonReset.setOnClickListener(buttonListener)
    }

    /**
     * 三個按鈕共用的點擊事件監聽器。
     *
     * inner 讓 MyButton 可以存取 MainActivity 的
     * textViewCounter 等成員。
     */
    inner class MyButton : View.OnClickListener {

        override fun onClick(view: View?) {

            // view 代表目前被使用者點擊的元件。
            // 讀取 view.id 後,使用 when 判斷按鈕功能。
            when (view?.id) {

                R.id.button_plus -> {

                    // 讀取 TextView 目前顯示的文字。
                    val data =
                        textViewCounter.text.toString()

                    // 使用 toIntOrNull() 安全轉換成整數。
                    // 如果轉換失敗,就使用預設值 0。
                    var number =
                        data.toIntOrNull() ?: 0

                    // 數值加一。
                    number++

                    // 將整數轉回字串並顯示。
                    textViewCounter.text =
                        number.toString()
                }

                R.id.button_minus -> {

                    // 讀取並轉換目前數值。
                    val data =
                        textViewCounter.text.toString()

                    var number =
                        data.toIntOrNull() ?: 0

                    // 只有大於零時才減一,
                    // 避免計數器出現負數。
                    if (number > 0) {
                        number--
                    }

                    // 顯示計算結果。
                    textViewCounter.text =
                        number.toString()
                }

                R.id.button_reset -> {

                    // 將計數器直接歸零。
                    val number = 0

                    textViewCounter.text =
                        number.toString()
                }
            }
        }
    }
}

參考資料:Android Developers-事件監聽器


計數器的資料轉換流程

TextView.text 的型別是 CharSequence,不能直接執行整數加法,因此必須先轉換成 String,再轉成 Int

val data = textViewCounter.text.toString()
var number = data.toIntOrNull() ?: 0

number++

textViewCounter.text = number.toString()

完整轉換流程如下:

TextView.text
→ CharSequence
→ String
→ Int
→ 執行加減運算
→ String
→ 寫回 TextView.text

使用 toIntOrNull()toInt() 更安全。若文字不是合法整數,toInt() 會產生 NumberFormatExceptiontoIntOrNull() 則會回傳 null,再由 Elvis 運算子 ?: 提供預設值。參考資料:Kotlin-toIntOrNull


為什麼使用 inner class?

Kotlin 的巢狀類別預設不會持有外部類別的參考,因此不能直接存取 MainActivity 的屬性。加上 inner 後,內部類別就能操作外部 Activity 的 textViewCounter。參考資料:Kotlin-Nested and inner classes

inner class MyButton : View.OnClickListener {
    override fun onClick(view: View?) {
        textViewCounter.text = "0"
    }
}

因為 MyButton 會持有 MainActivity 的參考,所以它的生命週期不應超過 Activity,否則可能造成記憶體無法釋放。這個範例的監聽器只由 Activity 畫面元件使用,因此符合一般使用方式。參考資料:Android Developers-記憶體管理概觀


使用 when 判斷按鈕 ID

多個按鈕共用同一個監聽器時,可以從 onClick()view 參數取得被點擊元件的 ID:

when (view?.id) {

    R.id.button_plus -> {
        // 加一
    }

    R.id.button_minus -> {
        // 減一
    }

    R.id.button_reset -> {
        // 歸零
    }
}

這種寫法適合功能相近、數量較多的按鈕。所有點擊行為集中在同一處,比較容易統一維護。參考資料:Kotlin-when 運算式


範例三:使用按鈕切換 ImageView 圖片

第三個範例在畫面中放置一個 ImageView、三個 Button 和一個 TextView。按下不同按鈕後,程式會切換圖片及說明文字。參考資料:Android Developers-ImageView

圖片必須先放入 Android 專案的 Drawable 資源目錄:

app/src/main/res/drawable/img1.jpg
app/src/main/res/drawable/img2.jpg
app/src/main/res/drawable/img3.jpg

Android 建置專案時,會為圖片產生對應的資源 ID,例如 R.drawable.img1。資源檔名只能使用小寫英文字母、數字及底線。參考資料:Android Developers-Drawable 資源

MainActivity(9).kt 完整程式

package com.example.widget_3

import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat

class MainActivity : AppCompatActivity() {

    // 顯示目前圖片的說明文字。
    private lateinit var textView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 啟用 Edge-to-Edge 顯示。
        enableEdgeToEdge()

        // 載入 Activity 的 XML 版面。
        setContentView(R.layout.activity_main)

        // 處理系統狀態列及導覽列範圍。
        ViewCompat.setOnApplyWindowInsetsListener(
            findViewById(R.id.main)
        ) { view, insets ->

            val systemBars =
                insets.getInsets(WindowInsetsCompat.Type.systemBars())

            view.setPadding(
                systemBars.left,
                systemBars.top,
                systemBars.right,
                systemBars.bottom
            )

            insets
        }

        // 取得顯示圖片的 ImageView。
        val imageView =
            findViewById<ImageView>(R.id.imageView)

        // 取得三個圖片切換按鈕。
        val button1 =
            findViewById<Button>(R.id.button)

        val button2 =
            findViewById<Button>(R.id.button2)

        val button3 =
            findViewById<Button>(R.id.button3)

        // 取得顯示圖片說明的 TextView。
        textView =
            findViewById(R.id.textView)

        // 按下第一個按鈕,顯示 img1。
        button1.setOnClickListener {

            imageView.setImageResource(
                R.drawable.img1
            )

            textView.text = "This is flower 1"
        }

        // 按下第二個按鈕,顯示 img2。
        button2.setOnClickListener {

            imageView.setImageResource(
                R.drawable.img2
            )

            textView.text = "This is flower 2"
        }

        // 按下第三個按鈕,顯示 img3。
        button3.setOnClickListener {

            imageView.setImageResource(
                R.drawable.img3
            )

            textView.text = "This is flower 3"
        }
    }
}

參考資料:Android Developers-ImageView.setImageResource


使用 setImageResource() 切換圖片

setImageResource() 可以將 Drawable 資源設定成 ImageView 顯示的圖片:

imageView.setImageResource(R.drawable.img1)

其中:

  • imageView:準備更新的圖片元件。
  • setImageResource():設定圖片資源的方法。
  • R.drawable.img1:Drawable 圖片的資源 ID。

參考資料:Android Developers-ImageView API

如果需要清除目前圖片,可以傳入 0

imageView.setImageResource(0)

setImageResource() 適合顯示 App 內建的 Drawable 資源。如果需要載入網路圖片或較大的照片,實務上通常會使用 Coil 或 Glide 等圖片載入函式庫,以便處理背景下載、快取及記憶體管理。參考資料:Android Developers-載入圖片


同時更新圖片與文字

按下按鈕時,可以在同一個 Lambda 中執行多個動作:

button1.setOnClickListener {

    // 切換 ImageView 圖片。
    imageView.setImageResource(R.drawable.img1)

    // 修改 TextView 說明。
    textView.text = "This is flower 1"
}

這種操作可以用於相簿、商品圖片、教學卡片或動植物圖鑑等功能。參考資料:Android Developers-回應點擊事件


範例四:ImageButton 與共用事件監聽器

第四個範例使用六個 ImageButton。這些圖片按鈕共同使用 MyImgButton 事件監聽器,再根據按鈕 ID 修改三個 TextView。參考資料:Android Developers-ImageButton

ImageButton 修改的 TextView 顯示內容
imageButton1 tv1 this is flower 1
imageButton2 tv2 this is flower 2
imageButton3 tv3 this is flower 3
imageButton4 tv1 this is flower 4
imageButton5 tv2 this is flower 5
imageButton6 tv3 this is flower 6

參考資料:Android Developers-View.OnClickListener

MainActivity(10).kt 完整程式

package com.example.widget_41f

import android.os.Bundle
import android.view.View
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.widget_41f.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    // 宣告 activity_main.xml 對應的 View Binding。
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 啟用 Edge-to-Edge。
        enableEdgeToEdge()

        // 建立 ActivityMainBinding。
        binding =
            ActivityMainBinding.inflate(layoutInflater)

        // 將 Binding 的根 View 設定成 Activity 畫面。
        setContentView(binding.root)

        // 處理狀態列與導覽列範圍。
        ViewCompat.setOnApplyWindowInsetsListener(
            binding.main
        ) { view, insets ->

            val systemBars =
                insets.getInsets(WindowInsetsCompat.Type.systemBars())

            view.setPadding(
                systemBars.left,
                systemBars.top,
                systemBars.right,
                systemBars.bottom
            )

            insets
        }

        // 設定第一個 TextView 的初始文字。
        binding.tv1.text = "1234"

        // 建立一個共用的 ImageButton 事件監聽器。
        val imageButtonListener = MyImgButton()

        // 六個 ImageButton 共用相同的監聽器物件。
        binding.imageButton1.setOnClickListener(
            imageButtonListener
        )

        binding.imageButton2.setOnClickListener(
            imageButtonListener
        )

        binding.imageButton3.setOnClickListener(
            imageButtonListener
        )

        binding.imageButton4.setOnClickListener(
            imageButtonListener
        )

        binding.imageButton5.setOnClickListener(
            imageButtonListener
        )

        binding.imageButton6.setOnClickListener(
            imageButtonListener
        )
    }

    /**
     * 六個 ImageButton 共用的點擊事件監聽器。
     *
     * 使用 inner 宣告後,可以直接存取
     * MainActivity 中的 binding。
     */
    inner class MyImgButton : View.OnClickListener {

        override fun onClick(view: View?) {

            // 根據被點擊 ImageButton 的 ID,
            // 決定要修改哪一個 TextView。
            when (view?.id) {

                R.id.imageButton1 -> {
                    binding.tv1.text =
                        "this is flower 1"
                }

                R.id.imageButton2 -> {
                    binding.tv2.text =
                        "this is flower 2"
                }

                R.id.imageButton3 -> {
                    binding.tv3.text =
                        "this is flower 3"
                }

                R.id.imageButton4 -> {
                    binding.tv1.text =
                        "this is flower 4"
                }

                R.id.imageButton5 -> {
                    binding.tv2.text =
                        "this is flower 5"
                }

                R.id.imageButton6 -> {
                    binding.tv3.text =
                        "this is flower 6"
                }
            }
        }
    }
}

參考資料:Android Developers-View BindingAndroid Developers-事件監聽器


為什麼共用同一個監聽器物件?

原始程式為每個按鈕各建立一個 MyImgButton

binding.imageButton1.setOnClickListener(MyImgButton())
binding.imageButton2.setOnClickListener(MyImgButton())
binding.imageButton3.setOnClickListener(MyImgButton())
binding.imageButton4.setOnClickListener(MyImgButton())
binding.imageButton5.setOnClickListener(MyImgButton())
binding.imageButton6.setOnClickListener(MyImgButton())

這樣可以正常運作,但會建立六個不同的監聽器物件。由於六個按鈕的事件都交給相同類別處理,因此可以只建立一次:

val imageButtonListener = MyImgButton()

binding.imageButton1.setOnClickListener(imageButtonListener)
binding.imageButton2.setOnClickListener(imageButtonListener)
binding.imageButton3.setOnClickListener(imageButtonListener)
binding.imageButton4.setOnClickListener(imageButtonListener)
binding.imageButton5.setOnClickListener(imageButtonListener)
binding.imageButton6.setOnClickListener(imageButtonListener)

共用物件能更明確表達「六個按鈕由同一個監聽器集中處理」的設計。參考資料:Android Developers-setOnClickListener


ImageView 與 ImageButton 的差異

比較項目 ImageView ImageButton
主要用途 顯示圖片 以圖片作為按鈕
是否預期互動 通常只顯示 主要用途就是點擊
常見用途 商品圖、照片、封面 播放、刪除、上一張
設定圖片 android:src android:src
點擊事件 可自行設定 通常都會設定
無障礙說明 建議設定 應設定清楚的功能說明

雖然 ImageView 也可以設定 setOnClickListener(),但如果元件的主要功能就是讓使用者點擊,使用 ImageButton 能更清楚地表達其用途。參考資料:Android Developers-ImageButton


為 ImageButton 加入無障礙說明

圖片按鈕沒有可直接閱讀的文字,因此應設定 android:contentDescription,讓 TalkBack 等螢幕閱讀器能說明按鈕功能。參考資料:Android Developers-描述 UI 元素

<ImageButton
    android:id="@+id/imageButton1"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:src="@drawable/img1"
    android:contentDescription="@string/show_flower_1" />

strings.xml

<resources>
    <string name="app_name">Widget Demo</string>
    <string name="show_flower_1">顯示第一張花朵圖片</string>
</resources>

不要只把圖片檔名當成 contentDescription。說明文字應描述按鈕執行的功能,例如「顯示第一張花朵圖片」或「切換到下一張圖片」。參考資料:Android Developers-讓 App 更容易使用


四個範例的事件處理方式比較

範例 主要元件 取得元件方式 事件處理方式
範例一 ButtonTextView View Binding 每個按鈕分別使用 Lambda
範例二 ButtonTextView findViewById() 共用 MyButton
範例三 ButtonImageView findViewById() 每個按鈕分別使用 Lambda
範例四 ImageButtonTextView View Binding 共用 MyImgButton

如果按鈕數量不多,而且每個按鈕的功能差異很大,可以分別使用 Lambda;如果有多個相同類型的按鈕,則可以共用 View.OnClickListener,再透過 when 依照 ID 分流。參考資料:Android Developers-回應點擊事件


Lambda 與共用 OnClickListener 比較

每個按鈕使用 Lambda

binding.button1.setOnClickListener {
    binding.textViewText1.text = "Button-1 Clicked"
}

binding.button2.setOnClickListener {
    binding.textViewText2.text = "Button-2 Clicked"
}

優點是簡單直覺,每一個按鈕的功能都寫在自己的區塊中,適合按鈕數量少、功能差異明顯的畫面。參考資料:Kotlin-Lambda expressions

多個按鈕共用 OnClickListener

val listener = MyButton()

buttonPlus.setOnClickListener(listener)
buttonMinus.setOnClickListener(listener)
buttonReset.setOnClickListener(listener)

優點是能集中處理同類型按鈕,適合計算機、數字鍵盤、圖片選單或功能面板等畫面。參考資料:Android Developers-View.OnClickListener


findViewById 與 View Binding 比較

比較項目 findViewById() View Binding
元件取得方式 手動輸入 ID 自動產生屬性
型別設定 需要指定型別 自動判斷型別
程式碼長度 較多 較精簡
ID 錯誤檢查 較有限 可在編譯階段檢查
新專案建議 可學習基本原理 建議優先使用

findViewById() 有助於初學者理解 XML ID 如何連接 Kotlin 元件;實際開發新專案時,View Binding 通常更安全,也可以減少重複程式碼。參考資料:Android Developers-View Binding


程式可以再怎麼改進?

目前計數器直接把數值存放在 TextView 中,每次點擊時都要先讀取文字再轉換成整數。更理想的方式是使用一個 Int 變數保存狀態,TextView 只負責顯示。參考資料:Android Developers-UI 狀態

// 使用變數保存真正的計數資料。
private var count = 0

/**
 * 將 count 的最新數值顯示在 TextView。
 */
private fun updateCounterText() {
    textViewCounter.text = count.toString()
}

按鈕事件可以改成:

when (view?.id) {

    R.id.button_plus -> {
        // 修改資料狀態。
        count++

        // 更新畫面。
        updateCounterText()
    }

    R.id.button_minus -> {
        // 確保數值不會低於零。
        if (count > 0) {
            count--
        }

        // 更新畫面。
        updateCounterText()
    }

    R.id.button_reset -> {
        // 重設資料。
        count = 0

        // 更新畫面。
        updateCounterText()
    }
}

這種設計把「資料」與「畫面顯示」分開,不必重複執行字串轉數字。日後進一步學習 ViewModelLiveDataStateFlow 時,也會延續相同的 UI 狀態管理觀念。參考資料:Android Developers-UI Layer


螢幕旋轉後計數器為什麼會歸零?

Android 裝置方向改變時,系統可能會銷毀並重新建立 Activity。若計數值只存放在 Activity 的一般變數中,重新建立後就會回到初始值。參考資料:Android Developers-Activity 狀態變更

簡單範例可以使用 onSaveInstanceState() 保存數值:

private var count = 0

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Activity 重新建立時,讀取先前保存的計數值。
    count = savedInstanceState?.getInt("count") ?: 0
}

override fun onSaveInstanceState(outState: Bundle) {

    // 在 Activity 可能被重新建立前保存目前數值。
    outState.putInt("count", count)

    super.onSaveInstanceState(outState)
}

較完整的 Android 架構通常會使用 ViewModel 保存畫面狀態,並搭配 SavedStateHandle 處理程序遭系統回收後的資料還原。參考資料:Android Developers-儲存 UI 狀態


今天學到的重點

今天透過四份 MainActivity 程式,完成了 Android Widget 與點擊事件的綜合練習:

  1. 使用 View Binding 操作 XML 元件。
  2. 使用 findViewById() 取得 ButtonTextViewImageView
  3. 使用 Lambda 處理簡單點擊事件。
  4. 使用 View.OnClickListener 建立共用監聽器。
  5. 使用 inner class 存取 Activity 的畫面元件。
  6. 使用 when 判斷被點擊按鈕的 ID。
  7. 製作增加、減少及歸零的計數器。
  8. 使用 toIntOrNull() 安全轉換數字。
  9. 使用 setImageResource() 動態切換 Drawable 圖片。
  10. 使用 ImageButton 建立圖片按鈕。
  11. 讓多個 ImageButton 共用相同監聽器。
  12. 為圖片按鈕加入 contentDescription
  13. 初步理解 UI 狀態與畫面顯示應分開管理。

參考資料:Android Developers-使用 Views 建構 UIAndroid Developers-輸入事件

今天的範例看似只是修改文字、增加數字和切換圖片,卻已經包含 Android App 最核心的互動流程:取得元件、監聽操作、修改資料,以及更新畫面。參考資料:Android Developers-UI Layer

下一篇有篇符可能繼續介紹 EditTextCheckBoxRadioButtonSwitchToast,讓 App 不只接收點擊,也能取得使用者輸入、處理選項並顯示操作訊息。參考資料:Android Developers-EditTextAndroid Developers-Toast


上一篇
Android Widget 實戰——計數器、圖片切換與共用按鈕事件
下一篇
Kotlin 物件導向進階——抽象類別、介面、Inner Class 與 Object
系列文
Android 鐵人賽: 天命最高 - 陪伴大家一步步打造屬於自己的app13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言